package parser.domain;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import main.Main;
import util.ParserUtil;

public class Follow {
	private Map<Symbol, Set<Symbol>> map;

	public Follow(Grammar gr, First first) {
		final Set<Production> productions = gr.getProductionRules();
		Set<NonTerminalSymbol> nonTerminals = gr.getNonTerminals();
		map = new HashMap<Symbol, Set<Symbol>>();
		Map<Symbol, Set<Symbol>> prevMap = new HashMap<Symbol, Set<Symbol>>();

		// L0 - initialization
		for (NonTerminalSymbol nonTerm : nonTerminals) {
			map.put(nonTerm, new HashSet<Symbol>());
		}
		map.get(gr.getStartingSymbol()).add(new TerminalSymbol(Main.EPSILON));

		Symbol y; // same in lecture notes
		int pos;
		do {
//			prevMap = new HashMap<Symbol, Set<Symbol>>(map);
			prevMap = ParserUtil.copyStepMap(map);

			for (NonTerminalSymbol nonTerm : nonTerminals) { // B in the lecture
																// notes
				for (Production prod : productions) {
					pos = prod.getRhs().indexOf(nonTerm);
					// if the rhs of the production contains the nonTerm and if
					// it is not at the last position
					if (-1 < pos && pos < prod.getRhs().size() - 1) {
						y = prod.getRhs().get(pos + 1);
						map.get(nonTerm).addAll(first.getFirst(y));
						if (first.getFirst(y).contains(
								new TerminalSymbol(Main.EPSILON))) {
							map.get(nonTerm).addAll(prevMap.get(prod.getLhs()));
						}
					} else if (pos > -1) {
						map.get(nonTerm).addAll(prevMap.get(prod.getLhs()));
					}
				}
			}
		} while (!ParserUtil.stepEquals(map, prevMap));

	}

	public Set<Symbol> getFollow(Symbol symbol) {
		return map.get(symbol);
	}

}
